package pyip.lib.javalearn.thread;

import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import pyip.lib.javalearn.Printer;

/**
 * 由于Junit退出时会调用System.exit(), 故不使用Junit.
 * @author yepeng
 * @date 2015年5月20日
 */
public class ThreadStateDemo {

    // 80000 约7s~8s
    @SuppressWarnings("unused")
    private static int business(int capacity) {
        // init array
        int[] array = new int[capacity];
        Random random = new Random();
        for (int i = 0; i < array.length; i++) {
            array[i] = random.nextInt(i + 1);
        }
        // sort
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] < array[j + 1]) {
                    int temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                }
            }
        }
        return array[0];
    }

    public static void main(String[] args) {
        Printer.out.println("main start", 0);
        // testRunnable();
        // testTimedWaiting();
        // testWait();
        testReentrantLock();

        Printer.out.println("main exit", 0);
    }

    public static void testRunnable() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Printer.out.println("t1 running state " + Thread.currentThread().getState(), 1);
                // business(80000);
                // Printer.out.println("t1 business finish", 1);
            }
        });
        Printer.out.println("main t1#new state " + t1.getState(), 0);
        t1.start();
        Printer.out.println("main t1#start state " + t1.getState(), 0);

    }

    public static void testTimedWaiting() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Printer.out.println("t1 sleep", 1);
                    Thread.sleep(5000);
                    Printer.out.println("t1 sleep finish", 1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Printer.out.println("main t1#sleep state " + t1.getState(), 0);
    }

    public static void testWait() {
        final Thread main = Thread.currentThread();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Printer.out.println("t1 start", 1);
                synchronized (main) {
                    try {
                        Printer.out.println("t1 obtained main", 1);
                        Printer.out.println("t1 main#wait", 1);
                        // state TIMED_WAITING
                        main.wait(1000);
                        // state WAITING
                        // main.wait();
                        Printer.out.println("t1 main#wait finish", 1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        synchronized (main) {
            t1.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Printer.out.println("main t1#synchronized state " + t1.getState(), 0);
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (main) {
            Printer.out.println("main t1#main.wait state " + t1.getState(), 0);
            main.notify();
            // t1的状态重新变成 BLOCKED
            Printer.out.println("main t1#main.notify state " + t1.getState(), 0);
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void testReentrantLock() {
        final Lock lock = new ReentrantLock();
        final Condition c1 = lock.newCondition();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                Printer.out.println("t1 start", 1);
                // state WAITING
                lock.lock();
                try {
                    Printer.out.println("t1 obtained lock", 1);
                    Printer.out.println("t1 await", 1);
                    // state TIMED_WAITING
                    c1.await(1, TimeUnit.SECONDS);
                    // state WAITING
                    // c1.await();
                    // state
                    // c1.awaitUninterruptibly();
                    Printer.out.println("t1 await finish", 1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        lock.lock();
        t1.start();
        try {
            Thread.sleep(100);
            Printer.out.println("main t1#lock state " + t1.getState(), 0);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.lock();
        try {
            Printer.out.println("main await state " + t1.getState(), 0);
            c1.signal();
            // 与synchronized 不一样, t1的状态不会发生变化, 保持为 WAITING 或 TIMED_WAITING
            Printer.out.println("main signal state " + t1.getState(), 0);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
